package hos.http;


import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.SystemClock;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;

import hos.http.converter.HttpConvert;


/**
 * <p>Title: HttpUtils </p>
 * <p>Description: 请求工具类 </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @version : 1.0
 * @date : 2023-02-24 13:49
 */
public class HttpUtils {

    /**
     * 拼装访问地址
     *
     * @param host 地址
     * @param path 路径
     * @return 访问地址
     */
    public static String url(String host, String path) {
        if (path == null || path.length() == 0) {
            return host;
        }
        if (host == null || host.length() == 0 ||
                path.contains("http") || path.contains("https")) {
            return path;
        }
        String hostNow = host;
        String pathNow = path;
        if (host.endsWith("/")) {
            hostNow = host.substring(0, host.length() - 1);
        }
        if (!pathNow.startsWith("/")) {
            pathNow = "/" + pathNow;
        }
        return hostNow + pathNow;
    }

    /**
     * 将Map转换为String
     *
     * @param list 需要转换的目标
     */
    public static String urlParam(List<HttpParam> list) {
        if (list == null) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        for (HttpParam httpParam : list) {
            String key = httpParam.getKey();
            Object value = httpParam.getValue();
            if (builder.length() != 0) {
                builder.append("&");
            }
            if (value != null) {
                builder.append(key).append("=").append(value);
            } else {
                builder.append(key).append("=").append("");
            }
        }
        return builder.toString();
    }

    /**
     * 将Map转换为String
     *
     * @param map 需要转换的目标
     */
    public static String urlParam(Map<String, ?> map) {
        Set<String> queryKeys = map.keySet();
        StringBuilder builder = new StringBuilder();
        for (String queryKey : queryKeys) {
            if (builder.length() != 0) {
                builder.append("&");
            }
            Object value = map.get(queryKey);
            if (value != null) {
                builder.append(queryKey).append("=").append(value);
            } else {
                builder.append(queryKey).append("=").append("");
            }
        }
        return builder.toString();
    }

    public static String parseUrl(String url) {
        if (!url.contains("?")) {
            return url;
        }
        return url.split("\\?")[0];
    }

    /**
     * 将String转换为Map
     *
     * @param url 需要转换的目标
     */
    public static Map<String, Object> parseUrlParam(String url) {
        if (!url.contains("?")) {
            return null;
        }
        String params = url.split("\\?")[1];
        String[] split = params.split("&");
        Map<String, Object> map = new LinkedHashMap<>();
        for (String item : split) {
            String[] itemSplit = item.split("=");
            map.put(itemSplit[0], itemSplit[1]);
        }
        return map;
    }

    /**
     * 将String转换为Map
     *
     * @param url 需要转换的目标
     */
    public static List<HttpParam> parseUrlHttpParam(String url) {
        if (!url.contains("?")) {
            return null;
        }
        String params = url.split("\\?")[1];
        String[] split = params.split("&");
        List<HttpParam> map = new LinkedList<>();
        for (String item : split) {
            String[] itemSplit = item.split("=");
            map.add(new HttpParam(itemSplit[0], itemSplit[1]));
        }
        return map;
    }

    public static Map<String, String> parseHeaders(Method method, String[] headers) {
        Map<String, String> headerMap = new LinkedHashMap<>();
        for (String header : headers) {
            int colon = header.indexOf(':');
            if (colon == -1 || colon == 0 || colon == header.length() - 1) {
                throw new IllegalArgumentException(
                        String.format("@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header)
                                + "\n    for method "
                                + method.getDeclaringClass().getSimpleName()
                                + "."
                                + method.getName());
            }
            String headerName = header.substring(0, colon);
            String headerValue = header.substring(colon + 1).trim();
            headerMap.put(headerName, headerValue);
        }
        return headerMap;
    }

    public static void progressListener(ProgressListener progressListener, Progress progress,
                                        long contentLength, long currentByteCount, long bytesRead) {
        if (progressListener == null) {
            return;
        }
        currentByteCount += ((bytesRead != -1L) ? bytesRead : 0);
        long currentElapsedTime = SystemClock.elapsedRealtime();
        progressListener.intervalByteCount += (bytesRead != -1L) ? bytesRead : 0;
        long currentInterval = currentElapsedTime - progressListener.elapsedTime;
        if (!progress.finish && (currentByteCount == contentLength || bytesRead == -1L || currentInterval >= progressListener.interval)) {
            if (currentByteCount == contentLength || bytesRead == -1L) {
                progress.finish = true;
            }
            progress.currentByteCount = currentByteCount;
            progress.totalByteCount = contentLength;
            progress.intervalByteCount = progressListener.intervalByteCount;
            progress.intervalTime = currentInterval;
            progressListener.onProgress(progress);
            progressListener.elapsedTime = currentElapsedTime;
            progressListener.intervalByteCount = 0L;
        }
    }

    public static void progressRequestBody(ConcurrentLinkedQueue<ProgressListener> progressListeners, Progress progress,
                                           long contentLength, long currentByteCount, long byteCount) {
        if (progressListeners == null || progressListeners.isEmpty()) {
            return;
        }
        currentByteCount += byteCount;
        long currentElapsedTime = SystemClock.elapsedRealtime();
        for (ProgressListener listener : progressListeners) {
            listener.intervalByteCount += byteCount;
            long currentInterval = currentElapsedTime - listener.elapsedTime;
            if (currentInterval >= listener.interval || currentByteCount == contentLength) {
                progress.currentByteCount = currentByteCount;
                progress.totalByteCount = contentLength;
                progress.intervalByteCount = listener.intervalByteCount;
                progress.intervalTime = currentInterval;
                HttpConfig.config().getMainThread().execute(new Runnable() {
                    @Override
                    public void run() {
                        listener.onProgress(progress);
                    }
                });
                listener.elapsedTime = currentElapsedTime;
                listener.intervalByteCount = 0L;
            }
        }
    }

    public static void progressResponseBody(ConcurrentLinkedQueue<ProgressListener> progressListeners, Progress progress,
                                            long contentLength, long currentByteCount, long bytesRead) {
        if (progressListeners == null || progressListeners.isEmpty()) {
            return;
        }
        currentByteCount += ((bytesRead != -1L) ? bytesRead : 0);
        long currentElapsedTime = SystemClock.elapsedRealtime();
        for (ProgressListener listener : progressListeners) {
            listener.intervalByteCount += (bytesRead != -1L) ? bytesRead : 0;
            long currentInterval = currentElapsedTime - listener.elapsedTime;
            if (!progress.finish && (currentByteCount == contentLength || bytesRead == -1L || currentInterval >= listener.interval)) {
                if (currentByteCount == contentLength || bytesRead == -1L) {
                    progress.finish = true;
                }
                progress.currentByteCount = currentByteCount;
                progress.totalByteCount = contentLength;
                progress.intervalByteCount = listener.intervalByteCount;
                progress.intervalTime = currentInterval;
                listener.onProgress(progress);
                listener.elapsedTime = currentElapsedTime;
                listener.intervalByteCount = 0L;
            }
        }
    }

    /**
     * 是否处于联网中
     *
     * @param context 上下文
     * @return true 联网中
     */
    public static boolean isNetworking(Context context) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Network networkCapabilities = connectivityManager.getActiveNetwork();
            if (networkCapabilities == null) {
                return false;
            }
            NetworkCapabilities actNw = connectivityManager.getNetworkCapabilities(networkCapabilities);
            if (actNw == null) {
                return false;
            }
            if (actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                return true;
            }
            if (actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                return true;
            }
            return actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET);
        } else {
            NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
            if (activeNetworkInfo == null) {
                return false;
            }
            return activeNetworkInfo.isConnected();
        }
    }

    /**
     * @noinspection unchecked
     */
    public static Object handleSuccess(HttpRequest<?> request, Object response) throws HttpException {
        try {
            HttpConvert<Object> httpConvert = (HttpConvert<Object>) request.getHttpConvert();
            Object responseNew;
            if (httpConvert != null) {
                responseNew = httpConvert.onConvert(request, request.getType(), response);
            } else {
                responseNew = response;
            }
            for (HttpInterceptor.ResponseInterceptor interceptor : request.getResponseInterceptor()) {
                interceptor.intercept(responseNew);
            }
            return responseNew;
        } catch (IOException e) {
            throw HttpException.throwResponse(request.getUrl(), e);
        }
    }

    public static void handleFailed(HttpRequest<?> request, Throwable throwable) {
        for (HttpInterceptor.ExceptionInterceptor interceptor : request.getExceptionInterceptor()) {
            interceptor.intercept(throwable);
        }
        HttpLogUtils.printStackTrace(throwable);
    }
}
